package org.example.gateway;

import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.example.gateway.contants.AdminConstants;
import org.example.gateway.contants.NacosConstants;
import org.example.gateway.exceptions.GatewayException;
import org.example.gateway.pojo.dto.RegisterAppDto;
import org.example.gateway.pojo.dto.UnregisterDto;
import org.example.gateway.utils.HttpUtil;
import org.example.gateway.utils.IPUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class AutoRegisterListener implements ApplicationListener {
    private static final Logger log = LoggerFactory.getLogger(AutoRegisterListener.class);

    private volatile AtomicBoolean registered = new AtomicBoolean(false);

    private final ClientConfigProperties properties;

    @NacosInjected
    private NamingService namingService;

    @Autowired
    private RequestMappingHandlerMapping handlerMapping;

    private final ExecutorService pool;

    private static List<String> ignoreUrlList = new LinkedList<>();

    static {
        ignoreUrlList.add("/error");
        ignoreUrlList.add("/user/add");
    }

    public AutoRegisterListener(ClientConfigProperties properties) {
        if (!check(properties)) {
            log.error("client config port,contextPath,appName adminUrl and version can't be empty!");
            throw new GatewayException("client config port,contextPath,appName adminUrl and version can't be empty!");
        }
        this.properties = properties;
        pool = new ThreadPoolExecutor(1, 4, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    }

    /**
     * 检查客户端配置项
     *
     * @param properties
     * @return
     */
    private boolean check(ClientConfigProperties properties) {
        if (properties.getPort() == null || properties.getContextPath() == null
                || properties.getVersion() == null || properties.getAppName() == null
                || properties.getAdminUrl() == null) {
            return false;
        }
        return true;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        if(!registered.compareAndSet(false, true)){
            return;
        }
        doRegister();
        registerShutdown();
    }

    /**
     * jvm关闭时向管理员发送注销请求
     */
    private void registerShutdown() {
        final String url = "http://" + properties.getAdminUrl() + AdminConstants.UNREGISTER_PATH;
        final UnregisterDto unregister = new UnregisterDto();
        unregister.setAppName(properties.getAppName());
        unregister.setVersion(properties.getVersion());
        unregister.setIp(IPUtil.getIpAddress());
        unregister.setPort(properties.getPort());
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            HttpUtil.doPost(url, unregister);
            log.info("[{}:{}] unregister from gateway-admin success!", unregister.getAppName(), unregister.getVersion());
        }));
    }

    /**
     *  注册所有接口信息到注册中心
     */
    private void doRegister() {
        Instance instance = new Instance();
        instance.setIp(IPUtil.getIpAddress());
        instance.setPort(properties.getPort());
        instance.setEphemeral(true);
        Map<String, String> metadataMap = new HashMap<>();
        metadataMap.put("version", properties.getVersion());
        metadataMap.put("appName", properties.getAppName());
        instance.setMetadata(metadataMap);
        try {
            namingService.registerInstance(properties.getAppName(), NacosConstants.APP_GROUP_NAME, instance);
        } catch (NacosException e) {
            log.error("register to nacos fail", e);
            throw new GatewayException(e.getErrCode(), e.getMessage());
        }
        log.info("register interface info to nacos success!");
        // 向 gateway-admin 发送注册请求
        String url = "http://" + properties.getAdminUrl() + AdminConstants.REGISTER_PATH;
        RegisterAppDto register = buildRegister(instance);
        HttpUtil.doPost(url, register);
        log.info("register to gateway-admin success!");
    }

    private RegisterAppDto buildRegister(Instance instance) {
        RegisterAppDto register = new RegisterAppDto();
        register.setAppName(properties.getAppName());
        register.setContextPath(properties.getContextPath());
        register.setIp(instance.getIp());
        register.setPort(instance.getPort());
        register.setVersion(properties.getVersion());
        return register;
    }


}
